﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;

namespace 串口助手
{
    public partial class Form1 : Form
    {
        private bool isOpen = false;

        private bool isRxShow = true;

        private List<byte> reciveBuffer = new List<byte>();

        private List<byte> sendBuffer = new List<byte>();

        private int reciveCount = 0;

        private int sendCount = 0;
        //SerialPort
        public Form1()
        {
            InitializeComponent();

            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            serialLoad();
        }

        /// <summary>
        /// 安全加载并刷新可用串口。如果没有串口不会抛出异常。
        /// 也会保留之前选择的端口（如果还存在）。
        /// </summary>
        private void serialLoad()
        {
            try
            {
                // 记录之前选择的端口，方便刷新后恢复选择
                string previousSelected = port_cbb.SelectedItem as string;

                // 使用 API 获取当前可用串口（比直接读注册表更可靠且兼容）
                string[] ports = SerialPort.GetPortNames();
                Array.Sort(ports, StringComparer.OrdinalIgnoreCase);

                port_cbb.Items.Clear();
                foreach (var p in ports)
                {
                    port_cbb.Items.Add(p);
                }

                if (port_cbb.Items.Count > 0)
                {
                    if (!string.IsNullOrEmpty(previousSelected) && port_cbb.Items.Contains(previousSelected))
                    {
                        port_cbb.SelectedItem = previousSelected;
                    }
                    else
                    {
                        port_cbb.SelectedIndex = 0;
                    }
                }
                else
                {
                    // 没有可用串口时清空选择，避免 SelectedIndex=0 抛出异常
                    port_cbb.Text = "";
                }

                // 下面为原来的默认下拉项设置，改为仅在有对应项时设置 SelectedIndex，避免 Count 为 0 导致异常
                if (baud_cbb.Items.Count > 1)
                    this.baud_cbb.SelectedIndex = 1;
                else if (baud_cbb.Items.Count > 0)
                    this.baud_cbb.SelectedIndex = 0;
                else
                    this.baud_cbb.SelectedIndex = -1;

                if (check_cbb.Items.Count > 0)
                    this.check_cbb.SelectedIndex = 0;
                else
                    this.check_cbb.SelectedIndex = -1;

                if (databit_cbb.Items.Count > 3)
                    this.databit_cbb.SelectedIndex = 3;
                else if (databit_cbb.Items.Count > 0)
                    this.databit_cbb.SelectedIndex = 0;
                else
                    this.databit_cbb.SelectedIndex = -1;

                if (stopbit_cbb.Items.Count > 0)
                    this.stopbit_cbb.SelectedIndex = 0;
                else
                    this.stopbit_cbb.SelectedIndex = -1;
            }
            catch (Exception)
            {
                // 静默吞掉异常，避免程序启动失败。可在需要时记录日志。
            }
        }

        private void sendData()
        {

            serialPort1.Write(sendBuffer.ToArray(),0,sendBuffer.Count);
            sendCount += sendBuffer.Count;
            recivecount_tssl.Text = sendCount.ToString();
        }

        private void send_btn_Click(object sender, EventArgs e)
        {
            // 如果发送的数据不为空，则接收
            if (this.send_rtb.Text != "" && serialPort1.IsOpen)
            {
                Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                sendData();
            }
            else
            {
                MessageBox.Show("请先输入发送数据！");

            }
        }

        private void open_btn_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen == false)
                {
                    serialPort1.PortName = port_cbb.Text;
                    serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);
                    serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);
                    switch (check_cbb.SelectedIndex)
                    {
                        //  none  odd  even 
                        case 0:
                            serialPort1.Parity = Parity.None;
                            break;
                        case 1:
                            serialPort1.Parity = Parity.Odd;
                            break;
                        case 2:
                            serialPort1.Parity = Parity.Even;
                            break;
                        default:
                            serialPort1.Parity = Parity.None;
                            break;
                    }
                    switch (stopbit_cbb.SelectedIndex)
                    {
                        // 1 1.5 2
                        case 0:
                            serialPort1.StopBits = StopBits.One;
                            break;
                        case 1:
                            serialPort1.StopBits = StopBits.OnePointFive;
                            break;
                        case 2:
                            serialPort1.StopBits = StopBits.Two;
                            break;
                        default:
                            serialPort1.StopBits = StopBits.One;
                            break;
                    }

                    serialPort1.Open();
                    isOpen = true;
                    open_btn.Text = "关闭串口";


                }
                else
                {
                    serialPort1.Close();
                    isOpen = false;
                    open_btn.Text = "打开串口";

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString()+serialPort1.PortName.ToString());
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (isRxShow == false) return;
            // 1,需要读取有效的数据 BytesToRead
            byte[] dataTemp = new byte[serialPort1.BytesToRead];
            serialPort1.Read(dataTemp,0,dataTemp.Length);

            reciveBuffer.AddRange(dataTemp);

            reciveCount += dataTemp.Length;

            this.Invoke(new EventHandler(delegate
            {
                // 显示接收数据的长度
                recivecount_tssl.Text = reciveCount.ToString();

                if (!recivehex_chb.Checked)
                {
                    // 2, 编码格式的选择
                    string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);
                    // 3，0x00 -> \0 结束 不会显示
                    str=str.Replace("\0", "\\0");

                    recive_rtb.AppendText(str);

                   // recive_rtb.AppendText(Encoding.GetEncoding("gb2312").GetString(dataTemp).Replace("\0", "\\0"));
                }
                else
                {
                    //  十六进制是选中的状态下
                    recive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));
                }

            }));
        }

        private void stop_btn_Click(object sender, EventArgs e)
        {
            if (isRxShow == true)
            {
                isRxShow = false;
                stop_btn.Text = "取消暂停";
            }
            else
            {
                isRxShow = true;
                stop_btn.Text = "暂停";
            }
        }

        private void recivehex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (recive_rtb.Text == "") return;
            if (recivehex_chb.Checked)
            {
                recive_rtb.Text = Transform.ToHexString(reciveBuffer.ToArray()," ");
            }
            else
            {
                recive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(reciveBuffer.ToArray()).Replace("\0","\\0");
            }
        }

        private void clear_btn_Click(object sender, EventArgs e)
        {
            reciveBuffer.Clear();
            recivecount_tssl.Text = "";
            recive_rtb.Text = "";
        }

        private void autoclear_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (autoclear_chb.Checked)
            {


                timer1.Start();
            }
            else
            {
                timer1.Stop();
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (recive_rtb.Text.Length > 4096)
            {
                reciveBuffer.Clear();
                recive_rtb.Text = "";
                recivecount_tssl.Text = "";
            }
        }

        private void send_rtb_Leave(object sender, EventArgs e)
        {
            if (sendhex_chb.CheckState == CheckState.Checked)
            {
                if (DataEncoding.IsHexString(send_rtb.Text.Replace(" ", "")))
                {
                    sendBuffer.Clear();
                    sendBuffer.AddRange(Transform.ToBytes(send_rtb.Text.Replace(" ", "")));

                }
                else
                {
                    MessageBox.Show("请输入正确的十六进制数据！！");
                    send_rtb.Select();
                }
            }
            else
            {
                sendBuffer.Clear();
                sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(send_rtb.Text));
            }
        }

        private void send_rtb_TextChanged(object sender, EventArgs e)
        {
            // 十六进制切换 会出现问题  这问题就是0x00 转换
        }

        private void sendhex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (send_rtb.Text == "") return;

            if (sendhex_chb.Checked == true)
            {
                send_rtb.Text = Transform.ToHexString(sendBuffer.ToArray(), " ");
            }
            else 
            { 
                send_rtb.Text = Encoding.GetEncoding("gb2312").GetString(sendBuffer.ToArray()).Replace("\0","\\0");

            }
        }

        private void sendclear_btn_Click(object sender, EventArgs e)
        {
            sendBuffer.Clear();

            send_rtb.Text = "";

            sendCount = 0;

            recivecount_tssl.Text = "0";
        }

        // 重写 WndProc，监听设备变更并刷新串口列表
        protected override void WndProc(ref Message m)
        {
            const int WM_DEVICECHANGE = 0x0219;
            const int DBT_DEVICEARRIVAL = 0x8000;
            const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
            const int DBT_DEVNODES_CHANGED = 0x0007;

            if (m.Msg == WM_DEVICECHANGE)
            {
                int wParam = m.WParam.ToInt32();
                if (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE || wParam == DBT_DEVNODES_CHANGED)
                {
                    // 在 UI 线程异步刷新，避免阻塞或线程问题
                    try
                    {
                        this.BeginInvoke(new Action(() => serialLoad()));
                    }
                    catch { }
                }
            }

            base.WndProc(ref m);
        }

        private void groupBox5_Enter(object sender, EventArgs e)
        {

        }
    }
}
